<!doctype html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>HolliEBR问题统计分析</title>
    <style type="text/css">
      .loader {
        border: 16px solid #f3f3f3;
        border-radius: 50%;
        border-top: 16px solid #3498db;
        width: 64px;
        height: 64px;
        -webkit-animation: spin 2s linear infinite;
        /* Safari */
        animation: spin 2s linear infinite;
      }

      @keyframes spin {
        0% {
          transform: rotate(0deg);
        }

        100% {
          transform: rotate(360deg);
        }
      }

      .progress {
        position: relative;
        display: inline;
        clear: both;
        float: left;
        width: 100px;
        height: 20px;
        border: 1px solid #ccc;
        background: #f7f7f7;
      }

      .progress-bar {
        position: absolute;
        background: #8DC643;
        ;
      }

      table a {
        text-decoration: none;
        color: #000;
      }

      #issue-table tr:first-child,
      #member-table tr:first-child {
        font-weight: 300;
      }

      #issue-table tr:last-child,
      #member-table tr:last-child {
        font-weight: bold;
        background: #fee;
      }

      #issue-table tr:nth-child(4n+8) {
        background: #FFFFC2;
      }

      #issue-table tr:nth-child(1) td:nth-child(3),
      #issue-table tr:nth-child(4n+8) td:nth-child(2) {
        font-weight: bold;
      }

    </style>

    <script type="text/javascript">

      async function Ajax(url = '', data = {}, type = 'GET', method = 'fetch') {
        // handle form-datas
        type = type.toUpperCase()
        let sendData

        if (type == 'GET') {
          let _data = []
          Object.keys(data).forEach(key => {
            _data.push(key + '=' + data[key])
          })
          url = url + '?' + _data.join('&')
        } else {
          sendData = JSON.stringify(data)
        }

        // build an object for ajax request
        if (window.fetch && method == 'fetch') {
          let reqConfig = {
            //credentials: 'include',
            method: type,
            headers: {
              'Accept': 'application/json',
              'Content-type': 'application/json'
            },
            mode: 'cors',
            cache: 'force-cache'
          }

          try {
            const response = await fetch(url, reqConfig)
            const responseJson = await response.json()

            return responseJson
          } catch (error) {
            throw new Error(error)
          }
        } else {
          return new Promise((resolve, reject) => {
            let reqObj

            if (window.XMLHttpRequest) {
              reqObj = new XMLHttpRequest()
            } else {
              reqObj = new ActiveXObject('Microsoft.XMLHTTP')
            }

            reqObj.open(type, url, true)
            reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
            reqObj.send(sendData)

            reqObj.onreadystatechang_HTe = () => {
              if (reqObj.readyState == 4) {
                if (reqObj.status == 200) {
                  let res = reqObj.response
                  if (typeof res !== 'object') {
                    res = JSON.parse(res)
                  }
                  resolve(res)
                } else {
                  reject(reqObj)
                }
              }
            }
          })
        }

      }


      const hv = {
        server: {
          host: '172.21.55.10',
          ptoken: 'cn2JNWFiGkZ62kAM2vmr '
        },
        issue: {
          group_id: 52,
          goal: 0.97,
          filters: 'created_after=2020-01-01T08:00:00.000+08:00',
          hang_filter: 'created_after='
        },
        projects: [
          { 'id': 45, 'name': 'client-app', 'type': 'project', 'alias': 'EBR-APP' },
          { 'id': 46, 'name': 'client-admin', 'type': 'project', 'alias': 'EBR-ADMIN' }
        ],
        members: [
          { 'id': 'quantianchao', 'name': '权田超' }, 
          { 'id': 'baoxiu', 'name': '包秀' }, 
          { 'id': 'chenpeng', 'name': '陈鹏' }, 
          { 'id': 'liqi', 'name': '李琪' },
          { 'id': 'shanghao', 'name': '尚浩' }
        ],
        states: {
          eval: '待评估', hang: '挂起', solving: '待修改',
          solved: '已修改', testing: '待测试', passed: '测试通过',
          notfix: '不是问题', duplicated: '重复问题', unsupported: '不支持'
        },
        lang: {
          // Statistics
          item: '项目',
          group_undone: '未解决',
          group_done: '已解决',
          stat_undone: '小计',
          stat_done: '小计',
          stat_total: '总计',
          sub_total: '合计'
        }
      }


      const stats_labels = Object.values(hv.states), stats_keys = Object.keys(hv.states),
        stats_opend_keys = stats_keys.splice(-3), stats_prog_keys = stats_keys.slice(1, 4),
        stats_todo_keys = stats_keys.splice(0, 3);
      const api_base = `http://${hv.server.host}/api/v4`, api_uri = `/issues_statistics?`;

      hv.projects.forEach(item => {
        item.undone = item.unsupported = item.duplicated = item.notfix = item.hang = item.solving = item.eval = 0;
        item.done = item.passed = item.testing = item.solved = 0;
        item.total = 0;

        for (const el in hv.states) {
          const condition = stats_todo_keys.indexOf(el) < 0 ? hv.issue.filters : hv.issue.hang_filter;
          const req_url = `${api_base}/${item.type}s/${item.id}${api_uri}&${condition}&labels=BUG,${hv.states[el]}`;

          fetch(req_url, { method: 'get',headers:{"PRIVATE-TOKEN":hv.server.ptoken} })
            .then(function (response) {
              if (!response.ok) throw new Error(response.statusText)
              return response.json();
            }).then(function (j) {
              item[el] = stats_opend_keys.indexOf(el) < 0 ? j.statistics.counts.all : j.statistics.counts.opened;
            }).catch(function (err) {
              // Error :(
            });
        }
      });


      hv.members.forEach(item => {
        item.hang = item.total = item.solving = item.solved = 0;

        for (const el of stats_prog_keys) {
          const req_url = `${api_base}${api_uri}&scope=all&labels=BUG,${hv.states[el]}&assignee_username=${item.id}`;

          fetch(req_url, { method: 'get', async: true,headers:{"PRIVATE-TOKEN":hv.server.ptoken} })
            .then(function (response) {
              if (!response.ok) throw new Error(response.statusText)
              return response.json();
            }).then(function (j) {
              item[el] = j.statistics.counts.opened;
            }).catch(function (err) {
              // Error :(
            });
        }
      });


      setTimeout(function () {
        /* 1.ISSUE ANALYSIS */

        // Tramat Matrix
        const proj_keys = Object.keys(hv.projects[0]);
        proj_keys.splice(0, 3);
        let projects_arr = new Array();
        for (let i = 0; i < proj_keys.length; i++) {
          projects_arr[i] = [proj_keys[i]];
        }

        hv.projects.forEach((item, index) => {
          const values = Object.values(item).splice(4);
          item.undone = values.slice(0, 6).reduce((total, num) => total += num);
          item.done = values.slice(6).reduce((total, num) => total += num);
          item.total = values.reduce((total, num) => total += num);
          for (const i in proj_keys) {
            projects_arr[i][index + 1] = item[proj_keys[i]];
          }
        });

        // Print Issue Table
        let todo_body = ["<table id='issue-table' border='1' cellspacing='0' cellpadding='5' style='border-collapse:collapse'>", ''].join('');
        projects_arr.forEach(item => {
          todo_body += `<tr align="center">`;
          for (const i in item) {
            todo_body += `<td${i == 0 ? " align='left'" : ''}>${i == 0 ? hv.states[item[i]] || hv.lang['stat_' + item[i]] || '状态' : item[i]}</td>`;
          }
          todo_body += `</tr>`;
        });
        document.getElementById('totolist').innerHTML = todo_body + '</table>';

        // Insert Column and Merge Cells
        let it = document.getElementById('issue-table'), row0 = it.rows[0], row1 = it.rows[1], row8 = it.rows[8], rowz = it.rows[it.rows.length - 1];
        it.rows[0].cells.length;
        let thead = document.createElement("td");
        thead.innerHTML = hv.lang.item;
        thead.width = 80;
        row0.insertBefore(thead, row0.cells[0]);

        let td_undone = document.createElement("td");
        td_undone.innerHTML = hv.lang.group_undone;
        td_undone.setAttribute("rowspan", 7);
        row1.insertBefore(td_undone, row1.cells[0]);

        let td_done = document.createElement("td");
        td_done.innerHTML = hv.lang.group_done;
        td_done.setAttribute("rowspan", 4);
        row8.insertBefore(td_done, row8.cells[0]);

        rowz.cells[0].setAttribute("colspan", 2);


        /* 2. MILESTONE PLAN */
        const group = hv.projects[0], total = group.total || 0, done = group.done || 0, undone = group.undone || 0;
        const repair_rate = (done / total * 100).toFixed(0);
        const left_bug = Math.ceil(total * hv.issue.goal - done);

        document.getElementById('goal').innerText = hv.issue.goal * 100;
        document.getElementById('repair-rate').innerText = repair_rate;
        document.getElementById('left-bug').innerText = left_bug;

        /* 3. MEMBER PROGRESS */
        let team = { "solving": 0, "solved": 0 };
        let tbody = ["<table id='member-table' border='1' cellspacing='0' cellpadding='5' style='border-collapse:collapse'>",
          '<tr align="center"><td width="80">姓名</td><td width="50">总数</td><td>待修改</td><td>已修改</td><td>进度</td></tr>'].join('');
        hv.members.forEach(item => {
          let solving = item.solving, solved = item.solved;
          item.total = solving + solved;
          item.progress = (solving == solved) ? 100 : solved / (item.total || 0.001) * 100;

          team.solving += solving;
          team.solved += solved;

          tbody += ['<tr align="center">', `<td>${item.name}</td>`,
            `<td><a target="_blank" href="http://172.21.55.10/dashboard/issues?assignee_username=${item.id}&label_name[]=BUG">${item.total}</a></td>`,
            `<td><a target="_blank" href="http://172.21.55.10/dashboard/issues?assignee_username=${item.id}&label_name[]=BUG&label_name[]=${hv.states.solving}">${item.solving}</a></td>`,
            `<td><a target="_blank" href="http://172.21.55.10/dashboard/issues?assignee_username=${item.id}&label_name[]=BUG&label_name[]=${hv.states.solved}">${item.solved}</a></td>`,
            `<td><div class="progress"><div class="progress-bar" style='width:${item.progress}px;'> &nbsp; </div></td>`,
            '</tr>'].join('');
        });

        team.total = team.solving + team.solved;
        team.progress = team.solved / team.total * 100;
        tbody += `<tr align="center"><td>${hv.lang.sub_total}</td><td>${team.total}</td><td>${team.solving}</td><td>${team.solved}</td><td><div class="progress" style="border-color:#f96;"><div class="progress-bar" style='width:${team.progress}px;background:orange;'> &nbsp; </div></td></tr>`;
        document.getElementById('progress').innerHTML = tbody + '</table>';

      }, 500);

    </script>

  </head>

  <body>
    <div>
      <h3>
        <p>==== HolliView问题进度计划 ====</p>
        <h3>
          <h2>
            <p>
              <font color="#FF0000">本周解决率目标：<label id="goal">-</label>%</font>
            </p>
            <h2>
              <h2>
                <p>
                  <font color="#FF0000">当前解决率达成：<label id="repair-rate">-</label>%</font>
                </p>
                <h2>
                  <h2>
                    <p>
                      <font color="#FF0000">当前距目标个数：<label id="left-bug">-</label></font>
                    </p>
                    <h2>
                      <h2>
                        <p>
                          <font color="#FF0000"></font>
                        </p>
                        <h2>

                          <div style="display:none;">
                            <h3>
                              <p>======================</p>
                              <h3>
                                <h3>总体说明</h3>
                                <p>有效数：<label id="total">-</label></p>
                                <p>已解决：<label id="done">-</label></p>
                                <p>未解决：<label id="undone">-</label></p>
                          </div>

                          <h3>
                            <p>======================</p>
                            <h3>
                              <h3>问题统计分析</h3>
                              <div id="totolist">
                                <div class="loader"></div>
                              </div>

                              <h3>
                                <p>======================</p>
                                <h3>
                                  <h3>问题修改进度</h3>
                                  <div id="progress">
                                    <div class="loader"></div>
                                  </div>
    </div>
    <p> </p>
  </body>

</html>
